// 服务端

#include "Log.hpp"
#include "Common.hpp"
#include "UdpServer.hpp"
#include "Route.hpp"
#include "ThreadPool.hpp"
#include <iostream>
#include <memory>
#include <functional>

using namespace LogModel;
using namespace ThreadPoolModel;

// 往线程池中放的任务类型 , 因为 Thread 任务类型是这个
using task_type = std::function<void()>;

// 使用方式
void Usage()
{
    std::cerr << " Usage :  ./server port " << std::endl;
}

// ./server port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage();
        exit(USAGE_ERROR);
    }
    // 获取端口号 , 转成 uint16_t 的整数
    uint16_t port = std::stoi(argv[1]);

    Enable_Console_Log_Strategy();

    // 1 . 路由服务
    Route r;

    // 2 . 创建线程池 , 往线程池中放任务 -- 即 : 路由转发任务
    auto tp = ThreadPool<task_type>::GetInstance();

#if 0
    
    //服务端启动服务器
    //创建服务器对象 , 传任务 , 任务类型 -- void(string , InteInfo)
    // 通过 lambda 的方式将 UdpSever 类 , InteInfo 类 , Route 类三者关联起来了
#endif
    // std::unique_ptr<UdpServer> chatudp = std::make_unique<UdpServer>(port,
    //     [&r](int sockfd, const std::string &message, InteInfo &inte)
    //     {
    //         // 真正的处理任务的类
    //         r.MessageRoute(sockfd, message, inte);
    //     });


    //// 多线程 

    #if 0 
        UdpServer 中需要传的任务类型 : 
        // 1. (int sockfd , const std::string& ,InteInfo&)>;
        // 2. 但是现在是线程池 , 要把路由转发任务包装成任务 , 放到队列中
        // 所以 , 还要捕捉线程池 , 因为要用到里面的 Equeue
        使用 Route 参数用函数绑定 , bind 
        // 因为线程池构造的任务必须是 : void() 这样的类型 , 
        // 但 Route 是int sockfd , const std::string& ,InteInfo&  这样的类型
        // 所以 , 进行函数绑定 , 函数回调就不用传参了 , 这样就是 void() 类型
        // 才能回调 !!!!!!!!!
    #endif
    std::unique_ptr<UdpServer> charudp_tp = std::make_unique<UdpServer>(port , 
        [&r , &tp](int sockfd, const std::string &message, InteInfo &inte)
        {
            //函数绑定 , 绑定上面所以参数 , 将 Route 包装成 void() 的任务
            task_type task = std::bind(&Route::MessageRoute , &r , sockfd , message , inte);
            //任务入队列
            tp->Equeue(task);
        });



    // 启动服务器
    charudp_tp->Init();
    charudp_tp->Start();

    return 0;
}
